import { useLocalForageItem } from "@/hooks/useLocalForage";
import { useRefNow } from "@/hooks/useRefNow";
import { useEffect, useMemo, useState } from "react";
import { Paging } from "./Paging";

export function usePaging<T = {}, P = {}>(opts: {
  forage_key?: string;
  init_list?: T[] | (() => T[]);
  init_params?: P | null,
  ready?: boolean;
  forgiving?: boolean;
  page_size?: number;
  loader: (paging: Paging<T, P | null>) => Promise<T[]>;
  catcher?: (e: any) => void;
}) {
  const { forage_key, ready: init_ready, forgiving = true, init_list, init_params = null, page_size = 50, loader, catcher } = opts;

  const [total, set_total, total_ready = true] = forage_key ?
    useLocalForageItem<number>({
      key: forage_key + '.total',
      init: 0,
    }) : useState(0);

  const [list, set_list, list_ready = true] = forage_key ?
    useLocalForageItem<T[]>({
      key: forage_key,
      init: init_list
    }) : useState<T[] | null>(init_list || null);

  const [loading, set_loading] = useState(false);
  const [finish, set_finish] = useState(false);
  const _ref_loader = useRefNow(loader);
  const _ref_catcher = useRefNow(catcher)
  const paging = useMemo(() => {
    const paging = new Paging<T, P | null>(page_size, init_params, p => _ref_loader.current(p)).on_loading(r => set_loading(r.loading))
    const { set_total: old_set_total, load: old_load } = paging
    paging.set_total = (total: number) => {
      const ret = old_set_total.call(paging, total);
      set_total(total);
      return ret;
    }
    paging.load = async (a, b) => {
      try {
        const list = await old_load.call(paging, a, b)
        set_list(list)
        return list;
      } catch (e) {
        const catcher = _ref_catcher.current;
        if (forgiving && Paging.isForgivableError(e)) {
          return paging.items;
        } else if (catcher) {
          catcher(e)
        } else {
          throw e;
        }
        return paging.items
      }
    }
    paging.on_loading(r => set_loading(r.loading))
    paging.on_finish(r => set_finish(r.finish))
    return paging;
  }, []);

  useEffect(() => {
    if (!total_ready || !list_ready || !init_ready) return;
    paging.load(true, init_params)
  }, [list_ready, total_ready, init_ready])

  return { paging, list, set_list, total, set_total, list_ready, loading, finish } as const;
}
